// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "build/build_config.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/renderer/savable_resources.h"
#include "content/shell/browser/shell.h"
#include "net/base/filename_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"

namespace content {

class SavableResourcesTest : public ContentBrowserTest {
public:
    using UrlVectorMatcher = testing::Matcher<std::vector<GURL>>;

    void SetUpCommandLine(base::CommandLine* command_line) override
    {
        command_line->AppendSwitch(switches::kSingleProcess);
#if defined(OS_WIN)
        // Don't want to try to create a GPU process.
        command_line->AppendSwitch(switches::kDisableGpu);
#endif
    }

    // Test function GetAllSavableResourceLinksForCurrentPage with a web page.
    // We expect result of GetAllSavableResourceLinksForCurrentPage exactly
    // matches expected_resources_set.
    void GetSavableResourceLinksForPage(
        const base::FilePath& page_file_path,
        const UrlVectorMatcher& expected_resources_matcher,
        const UrlVectorMatcher& expected_subframe_urls_matcher)
    {
        // Convert local file path to file URL.
        GURL file_url = net::FilePathToFileURL(page_file_path);
        // Load the test file.
        NavigateToURL(shell(), file_url);

        PostTaskToInProcessRendererAndWait(base::Bind(
            &SavableResourcesTest::CheckResources, base::Unretained(this),
            page_file_path, expected_resources_matcher,
            expected_subframe_urls_matcher, file_url,
            shell()->web_contents()->GetMainFrame()->GetRoutingID()));
    }

    void CheckResources(const base::FilePath& page_file_path,
        const UrlVectorMatcher& expected_resources_matcher,
        const UrlVectorMatcher& expected_subframe_urls_matcher,
        const GURL& file_url,
        int render_frame_routing_id)
    {
        // Get all savable resource links for the page.
        std::vector<GURL> resources_list;
        std::vector<SavableSubframe> subframes;
        SavableResourcesResult result(&resources_list, &subframes);

        RenderFrame* render_frame = RenderFrame::FromRoutingID(render_frame_routing_id);

        ASSERT_TRUE(GetSavableResourceLinksForFrame(
            render_frame->GetWebFrame(), &result));

        EXPECT_THAT(resources_list, expected_resources_matcher);

        std::vector<GURL> subframe_original_urls;
        for (const SavableSubframe& subframe : subframes) {
            subframe_original_urls.push_back(subframe.original_url);
        }
        EXPECT_THAT(subframe_original_urls, expected_subframe_urls_matcher);
    }
};

IN_PROC_BROWSER_TEST_F(SavableResourcesTest,
    GetSavableResourceLinksWithPageHasValidStyleLink)
{
    base::FilePath page_file_path = GetTestFilePath("dom_serializer", "simple_linked_stylesheet.html");

    auto expected_subresources_matcher = testing::UnorderedElementsAre(
        net::FilePathToFileURL(GetTestFilePath("dom_serializer", "style.css")));

    auto expected_subframe_urls_matcher = testing::IsEmpty();

    GetSavableResourceLinksForPage(page_file_path, expected_subresources_matcher,
        expected_subframe_urls_matcher);
}

// Test function GetAllSavableResourceLinksForCurrentPage with a web page
// which has valid savable resource links.
IN_PROC_BROWSER_TEST_F(SavableResourcesTest,
    GetSavableResourceLinksWithPageHasValidLinks)
{
    base::FilePath page_file_path = GetTestFilePath("dom_serializer", "youtube_1.htm");

    auto expected_subresources_matcher = testing::UnorderedElementsAre(
        GURL("file:///c:/yt/css/base_all-vfl36460.css"),
        GURL("file:///c:/yt/js/base_all_with_bidi-vfl36451.js"),
        GURL("file:///c:/yt/img/pixel-vfl73.gif"));

    auto expected_subframe_urls_matcher = testing::UnorderedElementsAre(net::FilePathToFileURL(
        GetTestFilePath("dom_serializer", "youtube_2.htm")));

    GetSavableResourceLinksForPage(page_file_path, expected_subresources_matcher,
        expected_subframe_urls_matcher);
}

// Test function GetAllSavableResourceLinksForCurrentPage with a web page
// which does not have valid savable resource links.
IN_PROC_BROWSER_TEST_F(SavableResourcesTest,
    GetSavableResourceLinksWithPageHasInvalidLinks)
{
    base::FilePath page_file_path = GetTestFilePath("dom_serializer", "youtube_2.htm");

    auto expected_subresources_matcher = testing::IsEmpty();

    auto expected_subframe_urls_matcher = testing::IsEmpty();

    GetSavableResourceLinksForPage(page_file_path, expected_subresources_matcher,
        expected_subframe_urls_matcher);
}

} // namespace content
